//
// Created by xwt.
//

#include "http_server.hpp"
#include <ab_logger.hpp>
#include <utility>
#include "nlohmann/json.hpp"
#include "agent_types.hpp"
//#include <openssl/bio.h>
//#include <openssl/evp.h>
//#include <openssl/buffer.h>
#include <libgen.h>
#include "base64.hpp"

using json = nlohmann::json;

namespace anbantech {

        agent_data g_default_cov_payload{
                {0, 0},
                {
                        {"", "", ""},
                        {"", "", ""}
                },
                {
                        {
                                {{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}},
                                {0, 0},
                                {{0, 0, 0, 0, "", 0, 0}, {0, 0, 0, 0, "", 0, 0}},
                                {0, 0},
                                {0, 0},
                                {0, 0},
                                "element",
                                {{0, 0, 0, 0, "", 0, 0}, {0, 0, 0, 0, "", 0, 0}},
                                {0, 0},
                                0,
                                {0, 0},
                                "",
                                {0, 0},
                                {
                                        {0, 0, 0, 0, 0},
                                        {0, 0, 0, 0, 0},
                                        0
                                },
                                {""}
                        }
                },
                "2023-01-01:00:00:00",
                true,
                "2023-01-01:00:00:00",
                true,
                {"", "", ""},
                "2023-01-01:00:00:00",
                "",
                "",
                "",
                true,
                {},
                {},
                0,
        };

    void print_params(const httplib::Request &req, const std::string& funcname){
        LOG(DEBUG,"==============%s=================",funcname.c_str())
        LOG(DEBUG,"path:[%s]",req.path.c_str());
        for(auto& param:req.path_params){
            LOG(DEBUG,"path-param:[%s:%s]",param.first.c_str(),param.second.c_str());
        }
        for(auto& param:req.params){
            LOG(DEBUG,"req-param:[%s:%s]",param.first.c_str(),param.second.c_str());
        }
        LOG(DEBUG,"body:[%s]",req.body.c_str());
        LOG(DEBUG,"==============%s=================",funcname.c_str())
    }

    http_server::http_server(const std::string& cfg_path) : mcfgPath(cfg_path) { }

    int http_server::init() {
        int ret = -1;
        //被测目标接收corpus，存为文件 ， 调用target，设置target状态
        add_path_handler(HTTP_METHOD_POST, "/abfuzz/abproxy/v1/projects/:project_id/fuzzings/:fuzzing_id/corpus",
                         [this](auto &&PH1, auto &&PH2) {
                             handle_corpus_run(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
                         });
        //异步请求的执行结果
        add_path_handler(HTTP_METHOD_POST, "/abfuzz/abproxy/v1/executions/responses/:request_id",
                         [this](auto &&PH1, auto &&PH2) {
                             handle_execution_responses(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
                         });
        //运行模糊执行命令
        add_path_handler(HTTP_METHOD_POST, "/abfuzz/abproxy/v1/projects/:project_id/fuzzings/:fuzzing_id/execution:run",
                         [this](auto &&PH1, auto &&PH2) {
                             handle_run_execution(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
                         });
        //更新模糊执行命令
        add_path_handler(HTTP_METHOD_PUT, "/abfuzz/abproxy/v1/projects/:project_id/fuzzings/:fuzzing_id/executions",
                         [this](auto &&PH1, auto &&PH2) {
                             handle_update_execution(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
                         });
        //获取模糊执行结果
        add_path_handler(HTTP_METHOD_GET, "/abfuzz/abproxy/v1/projects/:project_id/fuzzings/:fuzzing_id/executions/:id",
                         [this](auto &&PH1, auto &&PH2) {
                             handle_get_execution(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
                         });
        //检测被目标是否ready
        add_path_handler(HTTP_METHOD_GET, "/abfuzz/abproxy/v1/projects/:project_id/fuzzings/:fuzzing_id/readiness",
                         [this](auto &&PH1, auto &&PH2) {
                             handle_readiness(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
                         });
        //fuzzing结束后清理资源
        add_path_handler(HTTP_METHOD_POST, "/abfuzz/abproxy/v1/projects/:project_id/fuzzings/:fuzzing_id:clean",
                         [this](auto &&PH1, auto &&PH2) {
                             handle_clean_fuzzing(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
                         });
        //ssrf 漏洞检测的url // 不实现
        add_path_handler(HTTP_METHOD_GET, "/v1/ssrf/:fuzzing_id/:payload_id",
                         [this](auto &&PH1, auto &&PH2) {
                             handle_url_ssrf(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
                         });
        //url跳转使用  //不实现
        add_path_handler(HTTP_METHOD_GET, "/v1/url_redirection",
                         [this](auto &&PH1, auto &&PH2) {
                             handle_url_redirection(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
                         });

        ret = mCfg.loadfile(mcfgPath);
        if(ret != 0) {
            LOG(ERROR,"load cfg error");
            return ret;
        }
        mPort = mCfg.mPort;

        ret = mShm.create(SHM_KEY, mCfg.mSharedMemSize);
        if(ret != 0) {
            LOG(ERROR,"create shm error");
            return ret;
        }

        std::vector<std::string> tmpenvs;
        for(int i=0; mCfg.mTargetEnv[i] != nullptr; ++i){
            char tmpchar[1024];
            snprintf(tmpchar, 1024, "%s=%d", mCfg.mTargetEnv[i], mShm.id());
            tmpenvs.push_back(tmpchar);
        }
        mEnvs = agent_cfg::create_char_arr_arr(tmpenvs);

        return 0;
    }


    void http_server::run() {
        setup_routes();
        mServer.listen("0.0.0.0", mPort);
        std::cout << "Server started on http://0.0.0.0:" << mPort << "/\n";
    }

    void http_server::add_path_handler(std::string method, std::string path, handler handle) {
        path_handler tmp{std::move(method), std::move(path), std::move(handle)};
        mPathHandler.push_back(tmp);

    }
    void http_server::handle_not_found(const httplib::Request &req, httplib::Response &res) {
        print_params(req,"NOT FOUND");
        res.status=404;
        res.set_content("",HTTP_CONTENT_TYPE_JSON);
    }

    void http_server::setup_routes() {
        // 注册处理函数到相应的路径和方法
        mServer.set_error_handler([this](auto &&PH1, auto &&PH2) {
            handle_not_found(std::forward<decltype(PH1)>(PH1), std::forward<decltype(PH2)>(PH2));
        });

        for (const auto& ph : mPathHandler)
        {
            if (ph.method==HTTP_METHOD_POST) {
                mServer.Post(ph.path, ph.handle);
            } else if (ph.method == HTTP_METHOD_PUT) {
                mServer.Put(ph.path, ph.handle);
            } else if (ph.method == HTTP_METHOD_GET) {
                mServer.Get(ph.path, ph.handle);
            } else if (ph.method == HTTP_METHOD_DELETE) {
                mServer.Delete(ph.path, ph.handle);
            } else if (ph.method == HTTP_METHOD_PATCH) {
                mServer.Patch(ph.path, ph.handle);
            }
        }
    }

    //异步请求的执行结果`
    void http_server::handle_execution_responses(const httplib::Request &req, httplib::Response &res) {

        print_params(req, "异步请求的执行结果");

        //DO NOTHING

        res.set_content(req.body, HTTP_CONTENT_TYPE_JSON);
    }

    //运行模糊执行命令
    void http_server::handle_run_execution(const httplib::Request &req, httplib::Response &res) {

        print_params(req,"运行模糊执行命令");

        //DO NOTHING

        res.set_content(req.body, HTTP_CONTENT_TYPE_JSON);

    }

    //更新模糊执行命令
    void http_server::handle_update_execution(const httplib::Request &req, httplib::Response &res) {


        print_params(req,"更新模糊执行命令");
        auto project_id = req.path_params.at("project_id");
        auto fuzzing_id = req.path_params.at("fuzzing_id");
        std::string plugin = req.params.equal_range("plugin").first->second;

        json payload ;//= json::parse(req.body);
//        std::cout << "http body:" << payload.dump() << std::endl;
        agent_data data = payload;
        //DO NOTHING

        payload = data;
        res.set_content(payload.dump(), HTTP_CONTENT_TYPE_JSON);
    }

    //获取模糊执行结果
    void http_server::handle_get_execution(const httplib::Request &req, httplib::Response &res) {


        print_params(req,"获取模糊执行结果");
        auto project_id = req.path_params.at("project_id");
        auto fuzzing_id = req.path_params.at("fuzzing_id");
        auto id = req.path_params.at("id");
//        std::string plugin = req.params.equal_range("plugin").first->second;

        agent_data data = g_default_cov_payload;
        auto *tmp = new unsigned char[mCfg.mSharedMemSize];
        memcpy(tmp, mShm.read(), mCfg.mSharedMemSize);
        data.bitMap = base64_encode(tmp,mCfg.mSharedMemSize);
        delete[] tmp;
        coverageParser cov;

        char tmp_path[SIZE_KB]={0};
        snprintf(tmp_path,SIZE_KB,"%s",mCfg.mTargetFullPath);
//        cov.parseCoverages(dirname(tmp_path));
        data.coverages = cov.Get(dirname(tmp_path));
        data.id=id;
        data.fuzzingId=fuzzing_id;
        data.projectId=project_id;
        data.dryrun= false;
        data.done=true;
        data.reproduce=true;
        data.doneTime=get_localtime();
        data.executeTime=get_localtime();
        data.createTime=get_localtime();

        json payload;
        payload = data;
        LOG(DEBUG,"handle_get_execution return ok");
        res.set_content(payload.dump(), HTTP_CONTENT_TYPE_JSON);
    }

    //检测被目标是否ready
    void http_server::handle_readiness(const httplib::Request &req, httplib::Response &res) {

        print_params(req,"检测被目标是否ready");

        //check target exist executable
        if (access(mCfg.mTargetFullPath, X_OK) == 0)
        {
            res.set_content("true", HTTP_CONTENT_TYPE_JSON);
        } else {
            res.set_content("false", HTTP_CONTENT_TYPE_JSON);
        }
    }

    //fuzzing结束后清理资源
    void http_server::handle_clean_fuzzing(const httplib::Request &req, httplib::Response &res) {

        print_params(req,"fuzzing结束后清理资源");
        char cmd[SIZE_KB]={};
        char tmp_path[SIZE_KB]={0};
        snprintf(tmp_path,SIZE_KB,"%s",mCfg.mTargetFullPath);
        if(access(tmp_path,F_OK)!=0){
            res.status = 500;
            return;
        }
        const char *path_ptr=dirname(tmp_path);
        snprintf(cmd,SIZE_KB,"find %s -name *.gcda |xargs rm -f",path_ptr);
        system(cmd);
        snprintf(cmd,SIZE_KB,"find %s -name *.gcov.json |xargs rm -f",path_ptr);
        system(cmd);

        res.set_content("", HTTP_CONTENT_TYPE_JSON);
    }
//ssrf  不实现
    void http_server::handle_url_ssrf(const httplib::Request &req, httplib::Response &res) {
        json response_payload;
        response_payload["description"] = "";
        res.set_content(response_payload.dump(), HTTP_CONTENT_TYPE_JSON);
    }
//url 不实现
    void http_server::handle_url_redirection(const httplib::Request &req, httplib::Response &res) {
        json response_payload;
        response_payload["description"] = "";
        res.set_content(response_payload.dump(), HTTP_CONTENT_TYPE_JSON);
    }

    int http_server::write_to_file(const std::string& filename, const std::string& content) {
        char tmp_path[256]={0};
        snprintf(tmp_path,256,"%s",filename.c_str());
        char* dir_path=dirname(tmp_path);
        if (access(dir_path,F_OK)!=0){
            char cmd[256]={0};
            snprintf(cmd,256,"mkdir -p %s",dir_path);
            LOG(DEBUG,"create path cmd:[%s]",cmd);
            system(cmd);
        }

        std::ofstream file(filename);
        if (file.is_open()) {
            file << content;
            file.close();
        } else {
            return -1;
        }
        return 0;
    }

    void http_server::handle_corpus_run(const httplib::Request &req, httplib::Response &res) {
        print_params(req,"handle_corpus_run");
        if (req.body.empty()) {
            res.status = 400;
            return;
        }
        json response_payload;
        //把req.body写文件
        std::cout << mCfg.mCorpusFullPath << std::endl;
        if(write_to_file(mCfg.mCorpusFullPath, req.body) == 0) {

            mbTargetCrashed = false;
            for(int i=0; mCfg.mTargetOption[i] != nullptr; ++i){printf("%s\t", mCfg.mTargetOption[i]);}
            for(int i=0; mEnvs[i] != nullptr; ++i){printf("%s\t", mEnvs[i]);}
            mSubprocess.start(mCfg.mTargetFullPath, mCfg.mTargetOption, mEnvs);
            mbTargetCrashed = mSubprocess.wait();
            if(mbTargetCrashed)
                response_payload["crashed"]=true;
            else
                response_payload["crashed"]=false;

            response_payload["msg"]="执行成功";

        } else {
            LOG(ERROR,"无法写入corpus");
            res.status = 500;
            response_payload["msg"]="无法写入corpus";
        }

        res.set_content(response_payload.dump(),HTTP_CONTENT_TYPE_JSON);
    }

    /* 按照格式获取当前系统时间 */
    char* http_server::get_localtime()
    {
        time_t now;
        struct tm *local_time;
        char format[30];
        static char date_str[35];

        /* 获取当前时间 */
        time(&now);
        local_time = localtime(&now);

        /* 设置所需格式 */
        strftime(format, sizeof(format), "%Y-%m-%dT%H:%M:%S%z", local_time);

        strftime(date_str, sizeof(date_str), format, local_time);

        return date_str;
    }

    http_server::~http_server() {
        agent_cfg::free_char_arr_arr(mEnvs);
    }


} // anbantech